﻿using UnityEngine;
using System;
using System.Net.Sockets;
using Google.Protobuf;
using System.Reflection;
using System.Collections;
using System.Net;

public class TCPClient : MonoSingleton<TCPClient>
{
    private Socket clientSocket;
    public IPEndPoint tcpIPEndPoint => clientSocket.LocalEndPoint as IPEndPoint;
    private NetPacket message;
    private Action<bool> connectCallback;
    public string token => SystemInfo.deviceUniqueIdentifier + "_" + System.Diagnostics.Process.GetCurrentProcess().Id;
    public bool isLogin = false;

    protected override void AutoInit()
    {
        //注册一些全局事件
        // NetMsgMgr.Instance.RegisterMsg(NetMsgID.ReconnectResponse, ReconnectResponse);
        // NetMsgMgr.Instance.RegisterMsg(NetMsgID.KickOutLogin, OnKickOut);
    }

    /// <summary>与服务器建立tcp连接</summary>
    /// <param name="callback">连接成功或失败后的回调函数</param>
    /// <param name="endClient">连接之前是否释放连接</param>
    public void ConnectServer()
    {
        if (IsConnected())
        {
            Debug.Log("Connected already");
            return;
        }
        message = new NetPacket();
        clientSocket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
        clientSocket.BeginConnect("81.71.139.34", 30001, ConnectCallBack, null); // TODO 81.71.139.34
    }

    //子线程
    private void ConnectCallBack(IAsyncResult asyncResult)
    {
        try
        {
            clientSocket.EndConnect(asyncResult);//连接失败会抛出异常

            GameManager.Instance.RunInMainThread(() => {
                StartCoroutine(nameof(SendHeartBeat));
                connectCallback?.Invoke(true);
                SendMessage(NetMsgID.CsLogin, new CS_Login {Token = token});
            });

            clientSocket.BeginReceive(message.buffer, message.Start, message.Remain, SocketFlags.None, RcvMessageCallBack, null);
        }
        catch (Exception e)
        {
            Debug.LogError("连接失败 " + e);
            GameManager.Instance.RunInMainThread(() => {
                connectCallback?.Invoke(false);
                Invoke(nameof(ConnectServer), 10f);
            });
        }
    }

    //子线程
    private void RcvMessageCallBack(IAsyncResult asyncResult)
    {
        try
        {
            int count = clientSocket.EndReceive(asyncResult);
            if (count <= 0)
            {
                Debug.LogWarning("服务器主动断开连接");
                GameManager.Instance.RunInMainThread(() => {
                    Disconnect();
                    Invoke(nameof(ConnectServer), 10f);
                });
                return;
            }
            message.UnpackMessage(count, HandleResponse);
            clientSocket.BeginReceive(message.buffer, message.Start, message.Remain, SocketFlags.None, RcvMessageCallBack, null);
        }
        catch (Exception e)
        {
            Debug.LogWarning("TCP Receive 异常" + e);
            GameManager.Instance.RunInMainThread(() => {
                Disconnect();
                Invoke(nameof(ConnectServer), 10f);
            });
        }
    }

    public void SendMessage(NetMsgID msgId, IMessage data)
    {
        if (!IsConnected())
        {
            return;
        }
        try
        {
            LogSend(msgId, data);
            byte[] buffer = NetPacket.PackMessage(msgId, data);
            clientSocket.Send(buffer);
        }
        catch (Exception e)
        {
            Debug.LogWarning("TCP Send 异常" + e);
        }
    }

    private void HandleResponse(byte byteMsgId, byte[] buff)
    {
        NetMsgID netMsgId = (NetMsgID)byteMsgId;
        LogRcv(netMsgId, buff);
        NetMsgHandler.Instance.HandleResp(netMsgId, buff);
        //MethodInfo Deserialize = typeof(NetPacket).GetMethod("Deserialize").MakeGenericMethod(Type.GetType(responseCode.ToString()));
        //IMessage message = Deserialize?.Invoke(typeof(NetPacket), new object[] { responseParams }) as IMessage;

        // IMessage data = null;
        // switch (responseCode)
        // {
        //     case NetMsgID.ScLogin:
        //         data = NetPacket.Deserialize<SC_Login>(responseParams);
        //         break;
        //     case NetMsgID.ScHeartBeat:
        //         data = NetPacket.Deserialize<SC_HeartBeat>(responseParams);
        //         break;
        // }
        // NetMsgMgr.Instance.RcvMsg(responseCode, data);
    }

    private void LogSend(NetMsgID msgId, IMessage data) {
        switch (msgId)
        {
            case NetMsgID.CsSyncState:
                break;
            default:
                Debug.Log($"-->tcp:{msgId}:{data}");
                break;
        }
    }

    private void LogRcv(NetMsgID msgId, byte[] data)
    {
        switch (msgId)
        {
            case NetMsgID.ScNtfStates:
                break;
            default:
                Debug.Log($"<--tcp:{msgId}:[...{data.Length}]");
                break;
        }
    }

    public bool IsConnected()
    {
        return clientSocket != null && clientSocket.Connected;
    }

    public void Disconnect()
    {
        StopCoroutine(nameof(SendHeartBeat));
        if (clientSocket != null)
        {
            try
            {
                isLogin = false;
                if (clientSocket.Connected)
                {
                    clientSocket.Shutdown(SocketShutdown.Both);
                    clientSocket.Close();   
                }
                clientSocket = null;
            }
            catch (Exception e)
            {
                Debug.LogWarning("关闭tcp连接异常:" + e);
            }
        }
    }

    private IEnumerator SendHeartBeat()
    {
        while (true)
        {
            SendMessage(NetMsgID.CsHeartBeat, new CS_HeartBeat());
            yield return new WaitForSecondsRealtime(5f);
        }
    }
}
